package view.swing;

import static util.Constants.BOARD_HEIGHT;
import static util.Constants.BOARD_WIDTH;

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;

import model.Bonus;
import model.iview.IBoard;
import model.iview.ITile;
import util.Coordinate;
import view.IBoardView;
import view.swing.tiles.Placeur;
import view.swing.tiles.TileDragDroppable;
import view.swing.tiles.TileDragHandler;
import view.swing.tiles.TilePanel;

public class BoardView implements IBoardView {

    JPanel boardPanel = new JPanel();

    @SuppressWarnings("serial")
    private static class Square extends JPanel implements TileDragDroppable {

        private static final Color NORMAL_COLOR = new Color(18, 188, 100);
        private static final Color TILE_TMP_COLOR = new Color(252, 247, 166);
        private static final Color TILE_COLOR = TILE_TMP_COLOR.brighter();
        private static final Color L_DBL_COLOR = new Color(0, 192, 255);
        private static final Color L_TPL_COLOR = new Color(0, 0, 255);
        private static final Color M_DBL_COLOR = new Color(255, 192, 224);
        private static final Color M_TPL_COLOR = new Color(255, 0, 0);
        private static final Color STAR_COLOR = M_DBL_COLOR;

        private ITile tile = null;
        private boolean fixedTile;
        private TileDragDroppable sourceDrop = null;
        private TilePanel tp;

        public Square() {
            super();
            this.fixedTile = false;
        }

        public Square(Bonus bonus) {
            this();
            setLayout(new CardLayout());
            setBackground(bonus);
            addMouseListener(new Placeur());
            setTransferHandler(new TileDragHandler());
            addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    if (e.getButton() == MouseEvent.BUTTON1) {
                        JComponent c = (JComponent) e.getSource();
                        TransferHandler handler = c.getTransferHandler();
                        handler.exportAsDrag(c, e, TransferHandler.MOVE);
                    }
                }
            });

        }

        private void setBackground(Bonus bonus) {
            switch (bonus) {
            case L_DBL:
                setBackground(L_DBL_COLOR);
                break;
            case L_TPL:
                setBackground(L_TPL_COLOR);
                break;
            case M_DBL:
                setBackground(M_DBL_COLOR);
                break;
            case M_TPL:
                setBackground(M_TPL_COLOR);
                break;
            case STAR:
                setBackground(STAR_COLOR);
                break;
            case USED:
                setBackground(TILE_COLOR);
            default:
                setBackground(NORMAL_COLOR);
            }
        }

        @Override
        public void clear() {
            this.removeAll();
            this.tile = null;
            this.updateUI();
        }

        @Override
        public ITile drag() {
            ITile tmp = this.tile;
            clear();
            return tmp;
        }

        @Override
        public void drop(ITile tile) {
            this.tile = tile;
            this.removeAll();

            tp = new TilePanel(tile);
            this.add(tp, "Center");

            this.updateUI();

        }

        @Override
        public AllowedState getAllowedState() {
            return fixedTile ? AllowedState.NONE : AllowedState.BOTH;
        }

        @Override
        public TileDragDroppable getSource() {
            return sourceDrop;
        }

        @Override
        public boolean hasTileHere() {
            return tile != null;
        }

        @Override
        public void setSource(TileDragDroppable tileSourceDrop) {
            if (!(tileSourceDrop instanceof Square)) {
                this.sourceDrop = tileSourceDrop;
            }
        }

        @Override
        public ITile getTile() {
            return tile;
        }

        public boolean isFixedTile() {
            return fixedTile;
        }

        public void setFixedTile(boolean fixedTile) {
            if (hasTileHere()) {
                this.fixedTile = fixedTile;
                tp.setNormal();
            }

            if (tile != null) {
                drop(tile);
            }
        }

        @Override
        public void setSelected(boolean selected) {
            if (tp == null)
                return;
            if (!selected) {
                tp.setNormal();
            } else {
                tp.setSelected();
            }
        }
    }

    private Square[][] squares = new Square[BOARD_HEIGHT][BOARD_WIDTH];

    public BoardView(IBoard boardModel) {

        GridLayout layout = new GridLayout(BOARD_WIDTH + 1, BOARD_HEIGHT + 1);
        layout.setHgap(1);
        layout.setVgap(1);
        boardPanel.setLayout(layout);
        String[] letters = new String[] { "A", "B", "C", "D", "E", "F", "G",
                "H", "I", "J", "K", "L", "M", "N", "O" };
        boardPanel.add(new JLabel(), null);
        for (int i = 0; i < BOARD_WIDTH; i++) {
            JLabel headLbl = new JLabel(letters[i]);
            headLbl.setHorizontalAlignment(SwingConstants.CENTER);
            boardPanel.add(headLbl, null);
        }
        for (int i = 1; i < BOARD_HEIGHT + 1; i++) {
            JLabel colLbl = new JLabel(String.valueOf(i));

            colLbl.setHorizontalAlignment(SwingConstants.CENTER);
            boardPanel.add(colLbl, null);
            for (int j = 0; j < BOARD_WIDTH; j++) {
                Coordinate c = new Coordinate(i - 1, j);
                Square sq = new Square(boardModel.getBonus(c));
                squares[i - 1][j] = sq;
                boardPanel.add(sq, null);
            }
        }

    }

    public JPanel getPanel() {
        return boardPanel;
    }

    /*
     * (non-Javadoc)
     * 
     * @see view.swing.IBoardView#getNewTiles()
     */
    public HashMap<Coordinate, ITile> getNewTiles() {
        HashMap<Coordinate, ITile> tiles = new HashMap<Coordinate, ITile>();
        int numCase = 0;
        for (int row = 0; row < squares.length; row++) {
            for (int col = 0; col < squares[row].length; col++) {
                ITile tileOnSquare = squares[row][col].getTile();
                if (tileOnSquare != null && !squares[row][col].isFixedTile()) {
                    tiles.put(new Coordinate(row, col), tileOnSquare);
                }
                numCase++;

            }
        }
        return tiles;
    }

    /*
     * (non-Javadoc)
     * 
     * @see view.swing.IBoardView#fixAllTiles()
     */
    public void fixAllTiles() {
        for (int row = 0; row < squares.length; row++) {
            for (int col = 0; col < squares[row].length; col++) {
                squares[row][col].setFixedTile(true);
                squares[row][col].updateUI();
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see view.swing.IBoardView#resetAllNonFixedTiles()
     */
    public void resetAllNonFixedTiles() {
        for (int row = 0; row < squares.length; row++) {
            for (int col = 0; col < squares[row].length; col++) {
                if (squares[row][col].hasTileHere()
                        && squares[row][col].getSource() != null
                        && !squares[row][col].isFixedTile())
                    squares[row][col].getSource()
                            .drop(squares[row][col].drag());
            }
        }
    }

    public void resetJokers() {
        for (int row = 0; row < squares.length; row++) {
            for (int col = 0; col < squares[row].length; col++) {
                if (squares[row][col].hasTileHere() && squares[row][col].getTile().isOldJoker()) {
                    squares[row][col].getTile().clearJokerValue();
                }
            }
        }
    }
}
